// excerpts from http://code.google.com/p/muduo/
//
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
//
// Author: Shuo Chen (chenshuo at chenshuo dot com)

#include "Poller.h"

#include "Channel.h"
#include "logging/Logging.h"

#include <assert.h>
#include <poll.h>

using namespace learnmuduo;

Poller::Poller(EventLoop *loop) : ownerLoop_(loop) {}

Poller::~Poller() {}

// `Poller::poll()`是`Poller`的核心功能，它调用`poll(2)`获得当前活动的IO事件，然后填充调用方传入的`activeChannels`，并返回`poll(2)`return的时刻
muduo::Timestamp Poller::poll(int timeoutMs, ChannelList *activeChannels) {
  // XXX pollfds_ shouldn't change
  int numEvents = ::poll(&*pollfds_.begin(), pollfds_.size(), timeoutMs); // 调用系统poll并获取事件数; C++标准保证`std::vector`的元素排列跟数组一样; &*pollfds_.begin()是获得元素的首地址
  muduo::Timestamp now(muduo::Timestamp::now());
  if (numEvents > 0) {
    LOG_TRACE << numEvents << " events happended";
    fillActiveChannels(numEvents, activeChannels); // 填充活跃Channel列表
  } else if (numEvents == 0) {
    LOG_TRACE << " nothing happended";
  } else {
    LOG_SYSERR << "Poller::poll()";
  }
  return now;
}

// `fillActiveChannels()`遍历`pollfds_`，找出有活动事件的`fd`，把它对应的`Channel`填入`activeChannels`。
void Poller::fillActiveChannels(int numEvents,
                                ChannelList *activeChannels) const {
  for (PollFdList::const_iterator pfd = pollfds_.begin();
       pfd != pollfds_.end() && numEvents > 0; ++pfd) { // 遍历pollfd数组直到找到所有事件
    if (pfd->revents > 0) { // 当前fd有事件
      --numEvents; // 剩余事件计数递减: 为了提前结束循环，每找到一个活动`fd`就递减`numEvents`，这样当`numEvents`减为`0`时表示活动`fd`都找完了，不必做无用功。
      ChannelMap::const_iterator ch = channels_.find(pfd->fd); // 查找对应Channel
      assert(ch != channels_.end()); // 确认Channel存在
      Channel *channel = ch->second; // 获取Channel指针
      assert(channel->fd() == pfd->fd); // 再次校验fd一致
      channel->set_revents(pfd->revents); // 设置Channel的返回事件: 当前活动事件`revents`会保存在`Channel`中，供`Channel::handleEvent()`使用（`L47`）
      // pfd->revents = 0;
      activeChannels->push_back(channel); // 加入活跃列表
    }
  }
}

// 主要功能是负责维护和更新`pollfds_`数组
void Poller::updateChannel(Channel *channel) { // 更新或添加Channel
  assertInLoopThread(); // 确认在正确线程调用
  LOG_TRACE << "fd = " << channel->fd() << " events = " << channel->events();
  if (channel->index() < 0) { // 新注册的Channel. index初值为-1
    // a new one, add to pollfds_
    assert(channels_.find(channel->fd()) == channels_.end()); // 确认未注册过
    struct pollfd pfd; // 创建新的pollfd
    pfd.fd = channel->fd(); // 设置fd
    pfd.events = static_cast<short>(channel->events()); // 设置关注事件
    pfd.revents = 0; // 初始化返回事件
    pollfds_.push_back(pfd); // 加入pollfd数组
    int idx = static_cast<int>(pollfds_.size()) - 1; // 记录索引位置
    channel->set_index(idx); // 更新Channel索引
    channels_[pfd.fd] = channel; // 建立fd到Channel映射
  } else { // 已存在的Channel
    // update existing one
    assert(channels_.find(channel->fd()) != channels_.end()); // 确认已注册
    assert(channels_[channel->fd()] == channel); // 映射关系正
    int idx = channel->index(); // 取出索引
    assert(0 <= idx && idx < static_cast<int>(pollfds_.size())); // 校验索引合法
    struct pollfd &pfd = pollfds_[idx]; // 获取对应pollfd
    assert(pfd.fd == channel->fd() || pfd.fd == -1); // 确认fd匹配
    pfd.events = static_cast<short>(channel->events()); // 更新关注事件
    pfd.revents = 0; // 清零返回事件
    if (channel->isNoneEvent()) { // 若不关心任何事件
      // ignore this pollfd
      pfd.fd = -1; // 将fd置为-1以忽略
    }
  }
}
